package com.example.rabbitmq.starter.consumer;

import com.example.rabbitmq.starter.entity.MQConfigInfo;
import com.example.rabbitmq.starter.model.MessagePayload;
import com.example.rabbitmq.starter.service.FailedMessageService;
import com.example.rabbitmq.starter.service.MQConfigService;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * 抽象消息消费者类
 */
public abstract class AbstractMessageConsumer implements MessageConsumer {

    private final Logger log = LoggerFactory.getLogger(getClass());

    @Resource
    private ObjectMapper objectMapper;

    @Resource
    private FailedMessageService failedMessageService;

    @Resource
    private RabbitTemplate rabbitTemplate;

    @Resource
    private MQConfigService mqConfigService;

    /**
     * 消息监听器，接收队列消息并处理
     *
     * @param message 原始消息对象
     * @param channel 通道
     */
    public void onMessage(Message message, Channel channel) {
        long deliveryTag = message.getMessageProperties().getDeliveryTag();

        try {
            // 解析消息体
            MessagePayload messagePayload = objectMapper.readValue(message.getBody(), MessagePayload.class);

            // 记录消息接收
            log.info("接收到消息: messageId={}, type={}, businessId={}",
                    messagePayload.getId(), messagePayload.getType(), messagePayload.getBusinessId());

            // 处理消息
            boolean success = processMessage(messagePayload);

            if (success) {
                // 消息处理成功，确认消息
                log.info("消息处理成功，确认消息: messageId={}", messagePayload.getId());
                channel.basicAck(deliveryTag, false);
            }
            else {
                // 消息处理失败
                handleProcessFailure(messagePayload, "业务处理失败", deliveryTag, channel, message);
            }

        }
        catch (Exception e) {
            // 记录异常信息
            log.error("处理消息出现异常: {}", e.getMessage(), e);

            try {
                // 解析消息（可能在前面的过程中解析失败）
                MessagePayload messagePayload = objectMapper.readValue(message.getBody(), MessagePayload.class);
                handleProcessFailure(messagePayload, e.getMessage(), deliveryTag, channel, message);
            }
            catch (Exception parseEx) {
                log.error("解析消息失败，拒绝消息: {}", parseEx.getMessage());
                try {
                    // 无法解析，直接拒绝消息
                    channel.basicReject(deliveryTag, false);
                }
                catch (Exception rejectEx) {
                    log.error("拒绝消息失败: {}", rejectEx.getMessage());
                }
            }
        }
    }

    /**
     * 处理消息处理失败的情况
     *
     * @param messagePayload 消息体
     * @param errorMessage   错误信息
     * @param deliveryTag    消息标签
     * @param channel        通道
     * @param originalMessage 原始消息
     */
    private void handleProcessFailure(MessagePayload messagePayload, String errorMessage, 
                                    long deliveryTag, Channel channel, Message originalMessage) throws Exception {
        // 获取当前重试次数
        Integer retryCount = messagePayload.getRetryCount();
        Integer maxRetryCount = messagePayload.getMaxRetryCount();

        if (retryCount == null) {
            retryCount = 0;
        }

        if (maxRetryCount == null) {
            maxRetryCount = 3;
        }

        // 判断是否还可以重试
        if (retryCount < maxRetryCount) {
            // 更新重试次数并设置回消息对象中
            retryCount = retryCount + 1;
            messagePayload.setRetryCount(retryCount);

            log.warn("消息处理失败，准备重试: messageId={}, 当前重试次数={}, 最大重试次数={}", 
                    messagePayload.getId(), retryCount, maxRetryCount);

            try {
                // 确认并删除原消息，而不是拒绝它
                channel.basicAck(deliveryTag, false);
                
                // 重新发布到队列，确保重试计数被保存
                String queueName = getQueueName();

                // 使用RabbitTemplate重新发送消息
                rabbitTemplate.convertAndSend("", queueName, messagePayload);

                log.info("已将更新重试次数的消息重新发送到队列: {}", queueName);
            }
            catch (Exception e) {
                log.error("重新发送消息失败: {}", e.getMessage(), e);
                // 如果重新发送失败，将消息放回原队列
                channel.basicNack(deliveryTag, false, true);
            }
        }
        else {
            log.error("消息处理失败，超过最大重试次数: messageId={}, 最大重试次数={}", 
                    messagePayload.getId(), maxRetryCount);

            // 持久化失败消息
            failedMessageService.persistFailedMessage(messagePayload, errorMessage);

            // 直接确认消息
            channel.basicAck(deliveryTag, false);
        }
    }



    /**
     * 获取队列名称
     *
     * @return 队列名称
     */
    protected abstract String getQueueName();
}